/*
    Copyright (C) 2025 mio <stigma@disroot.org>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
#include "aster.h"

#include <tdeaboutapplication.h>
#include <tdeapplication.h>
#include <tdeaction.h>
#include <tdefiledialog.h>
#include <tdemenubar.h>
#include <tdepopupmenu.h>
#include <kkeydialog.h>

#include <tqlayout.h>

#include "playlist.h"

constexpr int CONTROL_HIDE_TIMER_MS = 2000;

Aster::Aster(TQWidget *parent, const char *name)
    : TDEMainWindow(parent, name)
    , m_controlTimer(-1)
{
    clearWFlags(WDestructiveClose);
    setMouseTracking(true);

    TQVBoxLayout *layout = new TQVBoxLayout(this);

    m_playlist = new Playlist(this);

    m_player = new VideoPlayer(this);
    m_player->setPlaylist(m_playlist);

    m_controlBar = new ControlBar(this);

    layout->addWidget(m_player, 1);
    layout->addWidget(m_controlBar);

    setupActions();

    connect(m_player, TQ_SIGNAL(lengthChanged(int)),
            m_controlBar, TQ_SLOT(lengthChanged(int)));
    connect(m_player, TQ_SIGNAL(tick(int64_t)),
            m_controlBar, TQ_SLOT(tick(int64_t)));
    connect(m_player, TQ_SIGNAL(stateChanged(int)),
            m_controlBar, TQ_SLOT(setState(int)));
    connect(m_player, TQ_SIGNAL(tracksChanged()),
            TQ_SLOT(slotUpdateTracks()));

    connect(m_controlBar, TQ_SIGNAL(pause()),
            m_player, TQ_SLOT(pause()));
    connect(m_controlBar, TQ_SIGNAL(play()),
            m_player, TQ_SLOT(play()));
    connect(m_controlBar, TQ_SIGNAL(stop()),
            m_player, TQ_SLOT(stop()));
    connect(m_controlBar, TQ_SIGNAL(seek(int)),
            m_player, TQ_SLOT(seek(int)));
    connect(m_controlBar, TQ_SIGNAL(volumeChanged(int)),
            m_player, TQ_SLOT(setVolume(int)));
    connect(m_controlBar, TQ_SIGNAL(muteChanged(bool)),
            m_player, TQ_SLOT(setMuted(bool)));

    connect(m_controlBar, TQ_SIGNAL(previous()),
            m_playlist, TQ_SLOT(previous()));
    connect(m_controlBar, TQ_SIGNAL(next()),
            m_playlist, TQ_SLOT(next()));

    setCaption("Aster Media Player");

    // Default Size
    resize(720, 480);
}

Aster::~Aster()
{
}

void Aster::playBD()
{
    m_player->openStream("bluray://");
}

void Aster::playDVD()
{
    m_player->openStream("dvd://");
}

void Aster::enqueFile(const KURL &path)
{
    m_playlist->append(path);
}

void Aster::mouseMoveEvent(TQMouseEvent *event)
{
    if (isFullScreen()) {
        killTimer(m_controlTimer);
        m_controlBar->show();
        m_controlTimer = startTimer(CONTROL_HIDE_TIMER_MS);
    }
    TQWidget::mouseMoveEvent(event);
}

void Aster::timerEvent(TQTimerEvent *event)
{
    if (event->timerId() == m_controlTimer) {
        killTimer(m_controlTimer);
        m_controlTimer = -1;
        m_controlBar->hide();
    }
}

void Aster::setupActions()
{
    auto fileMenu = new TDEPopupMenu(this);
    KStdAction::open(this, TQ_SLOT(slotOpen()), actionCollection())->plug(fileMenu);
    fileMenu->insertSeparator();
    KStdAction::close(this, TQ_SLOT(close()), actionCollection())->plug(fileMenu);
    fileMenu->insertSeparator();
    KStdAction::quit(kapp, TQ_SLOT(quit()), actionCollection())->plug(fileMenu);

    auto viewMenu = new TDEPopupMenu(this);
    KStdAction::fullScreen(this, TQ_SLOT(slotFullScreen()), actionCollection(), this, "fullscreen")->plug(viewMenu);

    auto audioMenu = new TDEPopupMenu(this);
    m_audioTrackMenu = new TDEPopupMenu(audioMenu);
    m_audioTrackMenu->setCheckable(true);
    m_audioTrackMenu->setEnabled(false);

    connect(m_audioTrackMenu, TQ_SIGNAL(activated(int)),
            TQ_SLOT(slotSetAudioTrack(int)));

    audioMenu->insertItem(i18n("Track"), m_audioTrackMenu);

    auto videoMenu = new TDEPopupMenu(this);
    m_videoTrackMenu = new TDEPopupMenu(videoMenu);
    m_videoTrackMenu->setEnabled(false);

    connect(m_videoTrackMenu, TQ_SIGNAL(activated(int)),
            TQ_SLOT(slotSetVideoTrack(int)));

    m_subtitleTrackMenu = new TDEPopupMenu(videoMenu);
    m_subtitleTrackMenu->setEnabled(false);

    connect(m_subtitleTrackMenu, TQ_SIGNAL(activated(int)),
            TQ_SLOT(slotSetSubtitleTrack(int)));

    videoMenu->insertItem(i18n("Track"), m_videoTrackMenu);
    videoMenu->insertItem(i18n("Subtitles"), m_subtitleTrackMenu);

    auto settingsMenu = new TDEPopupMenu(this);
    KStdAction::showMenubar(this, TQ_SLOT(slotShowMenubar()), actionCollection())->plug(settingsMenu);
    settingsMenu->insertSeparator();
    KStdAction::keyBindings(this, TQ_SLOT(slotConfigureShortcuts()), actionCollection())->plug(settingsMenu);

    new TDEAction(i18n("Play/Pause"), "media-playback-play", Key_Space, m_player, TQ_SLOT(pause()), actionCollection(), "play_pause");
    new TDEAction(i18n("Fast Forward"), "media-seek-forward", Key_Right, this, TQ_SLOT(slotForward()), actionCollection(), "fast_foward");
    new TDEAction(i18n("Fast Forward (1m)"), "media-seek-forward", Key_Up, this, TQ_SLOT(slotForward1()), actionCollection(), "fast_forward_1m");
    new TDEAction(i18n("Rewind"), "media-seek-backward", Key_Left, this, TQ_SLOT(slotRewind()), actionCollection(), "rewind");
    new TDEAction(i18n("Rewind (1m)"), "media-seek-backward", Key_Down, this, TQ_SLOT(slotRewind1()), actionCollection(), "rewind_1m");
    new TDEAction(i18n("Next"), "media-skip-forward", SHIFT | Key_Greater, m_playlist, TQ_SLOT(next()), actionCollection(), "next");
    new TDEAction(i18n("Previous"), "media-skip-backward", SHIFT | Key_Less, m_playlist, TQ_SLOT(previous()), actionCollection(), "previous");

    menuBar()->insertItem(i18n("&File"), fileMenu);
    menuBar()->insertItem(i18n("&View"), viewMenu);
    menuBar()->insertItem(i18n("&Audio"), audioMenu);
    menuBar()->insertItem(i18n("V&ideo"), videoMenu);
    menuBar()->insertItem(i18n("&Settings"), settingsMenu);
    menuBar()->insertItem(i18n("&Help"), helpMenu());
}

void Aster::slotConfigureShortcuts()
{
    KKeyDialog::configure(actionCollection());
}

void Aster::slotForward()
{
    m_player->seek(m_player->currentTime() + 5000);
}

void Aster::slotForward1()
{
    m_player->seek(m_player->currentTime() + 60000);
}

void Aster::slotFullScreen()
{
    auto fsAction = dynamic_cast<TDEToggleFullScreenAction *>(actionCollection()->action("fullscreen"));
    if (!fsAction) {
        return;
    }

    if (fsAction->isChecked()) {
        // Going full screen
        menuBar()->hide();
        m_player->showCursor();
        m_controlTimer = startTimer(CONTROL_HIDE_TIMER_MS);

        showFullScreen();
    } else {
        // Exiting full screen
        menuBar()->show();
        m_controlBar->show();
        m_player->showCursor();
        killTimer(m_controlTimer);
        m_controlTimer = -1;

        showNormal();
    }
}

void Aster::slotOpen()
{
    KURL::List url = KFileDialog::getOpenURLs(":aster", TQString::null, this);
    if (!url.isEmpty()) {
        m_playlist->append(url);
        m_player->play();
    }
}

void Aster::slotRewind()
{
    m_player->seek(m_player->currentTime() - 5000);
}

void Aster::slotRewind1()
{
    m_player->seek(m_player->currentTime() - 60000);
}

void Aster::slotSetAudioTrack(int id)
{
    m_audioTrackMenu->setItemChecked(m_player->activeAudioTrack(), false);
    m_player->setActiveAudioTrack(id);
    m_audioTrackMenu->setItemChecked(id, true);
}

void Aster::slotSetSubtitleTrack(int id)
{
    /* Plus 1 and subtract 1 to adjust for when we add subtitle tracks in slotUpdateTracks */
    m_subtitleTrackMenu->setItemChecked(m_player->activeSubtitleTrack() + 1, false);
    m_subtitleTrackMenu->setItemChecked(id, true);

    if (id == 0) {
        // Disable
        m_player->setActiveSubtitleTrack(-1);
    } else {
        m_player->setActiveSubtitleTrack(id - 1);
    }

}

void Aster::slotSetVideoTrack(int id)
{
    m_videoTrackMenu->setItemChecked(m_player->activeVideoTrack(), false);
    m_player->setActiveVideoTrack(id);
    m_videoTrackMenu->setItemChecked(id, true);
}

void Aster::slotShowMenubar()
{
    menuBar()->setShown(!menuBar()->isVisible());
}

void Aster::slotUpdateTracks()
{
    TQValueVector<MediaTrack> tracks = m_player->audioTracks();
    m_audioTrackMenu->setEnabled(tracks.count() > 0);
    m_audioTrackMenu->clear();

    for (const auto& track : tracks) {
        m_audioTrackMenu->insertItem(track.name, track.id);
    }

    m_audioTrackMenu->setItemChecked(m_player->activeAudioTrack(), true);
    if (tracks.count() == 1) {
        m_audioTrackMenu->setItemEnabled(m_player->activeAudioTrack(), false);
    }

    tracks = m_player->subtitleTracks();
    m_subtitleTrackMenu->setEnabled(tracks.count() > 0);
    m_subtitleTrackMenu->clear();

    m_subtitleTrackMenu->insertItem(i18n("None"), 0);
    m_subtitleTrackMenu->insertSeparator();

    /* Since the "Disable" option is at index 0, we want to ensure
     * all other track IDs will not be 0, so we add 1.
     */
    for (const auto& track : tracks) {
        m_subtitleTrackMenu->insertItem(track.name, track.id + 1);
    }

    m_subtitleTrackMenu->setItemChecked(m_player->activeSubtitleTrack() + 1, true);

    tracks = m_player->videoTracks();
    m_videoTrackMenu->setEnabled(tracks.count() > 0);
    m_videoTrackMenu->clear();

    for (const auto& track : tracks) {
        m_videoTrackMenu->insertItem(track.name, track.id);
    }

    m_videoTrackMenu->setItemChecked(m_player->activeVideoTrack(), true);
    if (tracks.count() == 1) {
        m_videoTrackMenu->setItemEnabled(m_player->activeVideoTrack(), false);
    }
}


#include "aster.moc"
